home *** CD-ROM | disk | FTP | other *** search
- ;$Author: DCODY $
- ;$Date: 17 Mar 1993 13:10:16 $
- ;$Header: X:/sccs/mvsound/mvsound.asv 1.9 17 Mar 1993 13:10:16 DCODY $
- ;$Log: X:/sccs/mvsound/mvsound.asv $
- ;
- ; Rev 1.9 17 Mar 1993 13:10:16 DCODY
- ; changed FindDMABuffer to pre-condition the buffer to align on a 4k page if
- ; the buffer size is greater that or equal to 4k. This will allow 4k DMA
- ; buffers to run under Windows is a DOS box.
- ;
- ; Rev 1.8 24 Feb 1993 16:15:28 DCODY
- ; removed clearing the dma buffer with 80 hex. removed a check on the smallest
- ; dma buffer allowed in findthedmabuffer routine.
- ;
- ; Rev 1.7 08 Dec 1992 16:55:46 DCODY
- ; moved externADDR macros for Borland link.
- ;
- ; Rev 1.6 24 Sep 1992 08:54:22 DCODY
- ; changed MVGetHardware to mvGetHardware
- ;
- ; Rev 1.5 12 Aug 1992 17:13:18 DCODY
- ; made call to mvgethardware use a zero (0) parameter to use the current base.
- ;
- ; Rev 1.4 17 Jul 1992 14:18:22 DCODY
- ; moved TheDMAchannel and TheIRQchannel out to another module. Made the
- ; hardware I/O relocatable. Made initmvsound recallable without ill effects.
- ;
- ; Rev 1.3 09 Jul 1992 10:07:50 DCODY
- ; corrected MV101 bit test and jumps
- ;
- ; Rev 1.2 26 Jun 1992 14:13:48 DCODY
- ; added the parameter to GetHWVersion call
- ;
- ; Rev 1.1 23 Jun 1992 17:06:04 DCODY
- ; PAS2 update
- ;
- ; Rev 1.0 15 Jun 1992 09:43:46 BCRANE
- ; Initial revision.
- ;$Logfile: X:/sccs/mvsound/mvsound.asv $
- ;$Modtimes$
- ;$Revision: 1.9 $
- ;$Workfile: mvsound.asm $
-
- page 64,131
- Title MVSOUND -- Pro Audio Spectrum Sound Support Code
-
- ; /*\
- ;---|*|----====< MVSOUND >====----
- ;---|*|
- ;---|*| This module contains the code for supporting PCM I/O.
- ;---|*|
- ;---|*| Media Vision, Inc. Copyright (c) 1991,1992. All Rights Reserved.
- ;---|*|
- ; \*/
-
- ;
- ; The following set of equates are used to control what routines are compiled
- ; by doing this, MVSOUND.ASM can contain all the necessary code in one file,
- ; but generate separate, linkable objects with just the necessary code.
- ;
- ALLOBJS = 0 ; individual objects are being built
- DATAOBJ = 0 ; data code to be compiled
- MISC1OBJ = 0 ; minimum code needed from the library
- MISC2OBJ = 0 ; other miscellaneous code
- PCMOBJ = 0 ; PCM code to be compiled
-
- ifdef BUILDDATA
- DATAOBJ = 1 ; data code to be compiled
- endif
-
- ifdef BUILDMISC1
- MISC1OBJ = 1 ; misc module #1 code to be compiled
- endif
-
- ifdef BUILDMISC2
- MISC2OBJ = 1 ; misc module #2 code to be compiled
- endif
-
- ifdef BUILDPCM
- PCMOBJ = 1 ; data code to be compiled
- endif
-
- ifdef BUILDALL
- ALLOBJS = 1 ; all objects are being built
- DATAOBJ = 1 ; data code to be compiled
- MISC1OBJ = 1 ; miscellaneous code to be compiled
- MISC2OBJ = 1 ; miscellaneous code to be compiled
- PCMOBJ = 1 ; PCM code to be compiled
- endif
-
- .xlist
- include model.inc
- include masm.inc
- include target.inc
- include state.inc
- include common.inc
- .list
-
- ;
- ; structure for pointing to the above table of DMA addresses
- ;
-
- dmaaddr struc
- _dmach db ? ; DMA channel selected
- _dmardstat db ? ; DMA read status
- _dmawrcntrl db ? ; DMA write command register
- _dmawreq db ? ; DMA write request register
- _dmawrsmr db ? ; DMA write single mask register
- _dmawrmode db ? ; DMA write mode register
- _dmaclear db ? ; DMA clear low/high flip-flop
- _dmardtemp db ? ; DMA read temp register
- _dmawrclr db ? ; DMA write master clear
- _dmaclrmsk db ? ; DMA clear mask register
- _dmawrall db ? ; DMA write all mask register bits
- dmaaddr ends
-
- ;
- ;---------------------------========================---------------------------
- ;---------------------------====< DATA SECTION >====---------------------------
- ;---------------------------========================---------------------------
- ;
- externADDR MVInitStatePtr ; pointer to the state table init code
- externADDR mvGetHWVersion ; returns the hardware bits
-
- if MODELSIZE eq 0
- .code
- else
- .data
- endif
-
- if DATAOBJ ; include if we are building DATA.OBJ
-
- ;
- ; These variables are DMA/Buffer control variables
- ;
- TheIRQMask db INT7MSK ; 8259 interrupt mask
-
- TheDMAMode db 00h ; 44h for input, 48h for output
- LinearPtr dd 0 ; holds linear address
- SegmentedPtr dd 0 ; holds segmented address (real mode)
- DMABuffLength dw 0 ; DMA Length (0 based) (MUST BE EVEN!)
- DMABuffDivides db 0 ; # of splits in the DMA buffer
-
- TheSampleRate dd 0 ; 3k through 88k
- StereoMono db 0 ; ff for mono, 00 for stereo
- PCMDirection db 0 ; bit mask for the DMA controller
- SampleSize db 0 ; sample size: 0=8,1=12,2=16
-
- public DMAAutoInit ; TRUE(0ffh) or FALSE(000h)
- DMAAutoInit db 0ffh ; to allow auto-init on DMA access
-
- UserRoutine dd 0 ; User Code
-
- StatusWord dw 0 ; Holds current status:
- ; ; 0 = inactive, available
- ; ; 1 = currently playing
- ; ; 2 = currently recording
-
- OldIRQRoutine dd 0 ; holds the original routine
-
- polledmask equ bICsamprate+bICsampbuff ; polled mask
- dmamask equ bICsampbuff ; dma mask
-
- DMAOUTPUT equ 0+dmamask ; DMA is used to drive the output
- POLLEDOUTPUT equ 0+polledmask ; Polling routine drives output
- DMAINPUT equ 1+dmamask ; DMA is used to read input
- POLLEDINPUT equ 1+polledmask ; Polling routine reads input
- TypeOfSetup db 0 ; polled/dma interrupt masks & stuff..
-
- public NumberOfInterrupts
- NumberOfInterrupts dw 0 ; number of interrupts that have occured
- ;
- ; These variables direct our code to the proper DMA channel
- ;
- OurDMAPageReg dw CH1PAGEREG ; default to DMA channel 1 page reg
- OurDMAddress dw DMAC1ADDR ; default to DMA channel 1 address reg
-
- ;
- ; table of address pointers to the various DMA 2 addresses
- ;
- public DMA1AddrTable
- DMA1AddrTable label byte
- db DEFAULTDMA ; DMA channel selected
- db DMARDSTAT ; DMA read status
- db DMAWRCNTRL ; DMA write command register
- db DMAWREQ ; DMA write request register
- db DMAWRSMR ; DMA write single mask register
- db DMAWRMODE ; DMA write mode register
- db DMACLEAR ; DMA clear low/high flip-flop
- db DMARDTEMP ; DMA read temp register
- db DMAWRCLR ; DMA write master clear
- db DMACLRMSK ; DMA clear mask register
- db DMAWRALL ; DMA write all mask register bits
- ;
- ; table of address pointers to the various DMA 2 addresses
- ;
- public DMA2AddrTable
- DMA2AddrTable label byte
- db DEFAULTDMA ; DMA channel selected
- db DMA2RDSTAT ; DMA read status
- db DMA2WRCNTRL ; DMA write command register
- db DMA2WREQ ; DMA write request register
- db DMA2WRSMR ; DMA write single mask register
- db DMA2WRMODE ; DMA write mode register
- db DMA2CLEAR ; DMA clear low/high flip-flop
- db DMA2RDTEMP ; DMA read temp register
- db DMA2WRCLR ; DMA write master clear
- db DMA2CLRMSK ; DMA clear mask register
- db DMA2WRALL ; DMA write all mask register bits
-
- public DMAPointer
- DMAPointer dw offset DMA1AddrTable ; default to channel 1 table
- ;
- ; working variables
- ;
- ;
- public TheIRQMask ; 8259 interrupt mask
- public TheDMAMode ; 55h for input, 59h for output
- public LinearPtr ; holds linear address
- public SegmentedPtr ; holds segmented address (real mode)
- public DMABuffLength ; DMA Length (0 based) (MUST BE EVEN!)
- public DMABuffDivides ; # of splits in the DMA buffer
- public TheSampleRate ; 3k through 88k
- public StereoMono ; ff for mono, 00 for stereo
- public PCMDirection ; bit mask for the DMA controller
- public SampleSize ; sample size: 0=8,1=12,2=16
- public DMAAutoInit ; TRUE/FALSE flag for DMA autoinit bit
- public UserRoutine ; User Code
- public StatusWord ; Holds current status:
- public OldIRQRoutine ; holds the original routine
- polledmask equ bICsamprate+bICsampbuff ; polled mask
- dmamask equ bICsampbuff ; dma mask
- DMAOUTPUT equ 0+dmamask ; DMA is used to drive the output
- POLLEDOUTPUT equ 0+polledmask ; Polling routine drives output
- DMAINPUT equ 1+dmamask ; DMA is used to read input
- POLLEDINPUT equ 1+polledmask ; Polling routine reads input
- public TypeOfSetup ; polled/dma interrupt masks & stuff..
- public NumberOfInterrupts ; number of interrupts that have occured
- public OurDMAPageReg ; default to DMA channel 1 page reg
- public OurDMAddress ; default to DMA channel 1 address reg
-
- else ; not building DATA.OBJ, declare all publics
-
- extrn DMAPointer :word ; pointer to the DMA address table
- extrn DMA1AddrTable :byte ; 1st DMA controller table
- extrn DMA2AddrTable :byte ; 2nd DMA controller table
- extrn TheIRQMask :byte ; 8259 interrupt mask
- extrn TheDMAMode :byte ; 55h for input, 59h for output
- extrn LinearPtr :dword ; holds linear address
- extrn SegmentedPtr :dword ; holds segmented address (real mode)
- extrn DMABuffLength :word ; DMA Length (0 based) (MUST BE EVEN!)
- extrn DMABuffDivides :byte ; # of splits in the DMA buffer
- extrn TheSampleRate :dword ; 3k through 88k
- extrn StereoMono :byte ; ff for mono, 00 for stereo
- extrn PCMDirection :byte ; bit mask for the DMA controller
- extrn SampleSize :byte ; sample size: 0=8,1=12,2=16
- extrn DMAAutoInit :byte ; TRUE/FALSE flag for DMA autoinit bit
- extrn UserRoutine :dword ; User Code
- extrn StatusWord :word ; Holds current status:
- extrn OldIRQRoutine :dword ; holds the original routine
- extrn TypeOfSetup :byte ; polled/dma interrupt masks & stuff..
- extrn NumberOfInterrupts:word ; number of interrupts that have occured
- extrn OurDMAPageReg :word ; default to DMA channel 1 page reg
- extrn OurDMAddress :word ; default to DMA channel 1 address reg
-
-
- polledmask equ bICsamprate+bICsampbuff ; polled mask
- dmamask equ bICsampbuff ; dma mask
- DMAOUTPUT equ 0+dmamask ; DMA is used to drive the output
- POLLEDOUTPUT equ 0+polledmask ; Polling routine drives output
- DMAINPUT equ 1+dmamask ; DMA is used to read input
- POLLEDINPUT equ 1+polledmask ; Polling routine reads input
- SHADOWTABLELEN equ 28 ; 28 entries in the shadow data table
-
- endif
-
- extrn TheDMAChannel :byte ; defaults to channel 1
- extrn TheIRQChannel :byte ; defaults to IRQ 7
-
- extrn mvhwShadowPointer :dword; a common variable for all
- extrn _MVHWVersionBits :word ; hardware state bits
- extrn _MVTranslateCode :word
-
- .code
-
- ;
- ; TEXT SEGMENT externals for the different modules
- ;
-
- if PCMOBJ AND (NOT ALLOBJS) ; added for independent PCMOBJ module
- externADDR SelectIRQ ; PCM uses "SelectIRQ"
- externADDR _unloadirqvector ; PCM uses "_unloadirqvector"
- externADDR _getirqoffset ; PCM uses "_getirqoffset"
- endif
-
- ;
- ;---------------------------========================---------------------------
- ;---------------------------====< CODE SECTION >====---------------------------
- ;---------------------------========================---------------------------
- ;
- ; /*\
- ;---|*|
- ;---|*|---------------====< Prototypes >====---------------
- ;---|*|
- ;---|*| void far *DMABuffer(char far *, int, int )
- ;---|*|
- ;---|*| Passes in a pointer and length to the buffer.
- ;---|*| Also flushes the buffer. Returns 0 or true DMA buffer ptr.
- ;---|*|
- ;---|*| int EnablePCMPlay()
- ;---|*|
- ;---|*| Sets up the PCM hardware for polled output
- ;---|*|
- ;---|*| int EnablePCMRecord()
- ;---|*|
- ;---|*| Sets up the PCM hardware for polled input
- ;---|*|
- ;---|*| char huge *FindDMABuffer(char huge *, int )
- ;---|*|
- ;---|*| Takes a memory address & return the next 64k boundary
- ;---|*|
- ;---|*| MVState far *InitMVSound()
- ;---|*|
- ;---|*| Initializes the int 2F interface & some global variables.
- ;---|*|
- ;---|*| int InitPCM()
- ;---|*|
- ;---|*| Initializes the PCM code.
- ;---|*|
- ;---|*| void PausePCM()
- ;---|*|
- ;---|*| Temporarily stops the PCM I/O by disabling the timers
- ;---|*|
- ;---|*| int PCMInfo( long ,int, int, int )
- ;---|*|
- ;---|*| Sets up the transfer rate & stereo/mono/compression/data size
- ;---|*|
- ;---|*| int PCMPlay()
- ;---|*|
- ;---|*| Starts the DMA feeding the DAC
- ;---|*|
- ;---|*| int PCMRecord()
- ;---|*|
- ;---|*| Starts the DMA reading the ADC
- ;---|*|
- ;---|*| void RemovePCM()
- ;---|*|
- ;---|*| kills the PCM code.
- ;---|*|
- ;---|*| void ResumePCM()
- ;---|*|
- ;---|*| Restarts the PCM I/O by enabling the timers
- ;---|*|
- ;---|*| int SelectDMA( int )
- ;---|*|
- ;---|*| Selects the DMA channel 1, or 3
- ;---|*|
- ;---|*| int SelectIRQ( int )
- ;---|*|
- ;---|*| Selects the IRQ line for DMA control
- ;---|*|
- ;---|*| void StopPCM()
- ;---|*|
- ;---|*| Turn off the PCM timers, interrupts, and state machine.
- ;---|*|
- ;---|*| void UserFunc((*long)())
- ;---|*|
- ;---|*| Call back routine when Half way buffer is full/empty.
- ;---|*|
- ; \*/
-
- if PCMOBJ
-
- ; /*\
- ;---|*|------====< void far * DMABuffer( char far *, int, int ) >====------
- ;---|*|
- ;---|*| Passes in a pointer and length to the buffer
- ;---|*|
- ;---|*| Entry Conditions:
- ;---|*| dParm1 points to DMA buffer
- ;---|*| wParm3 points to the length (wParm3 * 1024 is the total length )
- ;---|*| wParm4 is the # of divisions of the DMA buffer
- ;---|*|
- ;---|*| Exit Conditions:
- ;---|*| DX:AX = 0 - bad buffer
- ;---|*| DX:AX = returns buffer pointer
- ;---|*|
- ; \*/
-
- public DMABuffer
- DMABuffer proc
- push bp
- mov bp,sp
- push es
- push di
-
- mov cx,wParm3 ; get the dma size (4/8/16/32/64)
- cmp cx,64 ; too high?
- ja dmabbad ; yes, bomb out
-
- mov ax,1024
- cwd
- mul cx ; get the length - 1
- dec ax
- mov [DMABuffLength],ax ; and save for later use
-
- les di,dParm1 ; get the far pointer to the buffer
-
- mov ax,di
- mov bx,es ; convert it to a linear address
- mov dx,es
- mov cl,4
- rol dx,cl
- and dx,000fh
- shl bx,cl ; add offset portion of seg to offset
- add ax,bx
- jc dmabbad ; bad if extends over a 64k boundary
-
- mov wptr [LinearPtr+0],ax ; save the linear address
- mov wptr [LinearPtr+2],dx
- mov wptr [SegmentedPtr+0],di
- mov wptr [SegmentedPtr+2],es
-
- mov bx,wParm4 ; get the # of DMA buffer divisions
- mov [DMABuffDivides],bl
-
- push ax ; save the buffer offset
-
- ;;;;;;;;mov cx,[DMABuffLength] ; get the clearing length
- ;;;;;;;;mov al,80h ; PCM silent code
- ;;;;;;;;cld
- ;;;;;;;;rep stosb ; flush the buffer length...
- ;;;;;;;;stosb ; + 1
-
- mov dx,es
- pop ax ; return dx:ax
- jmp short dmabdone
- ;
- dmabbad:
- sub ax,ax
- cwd
- ;
- dmabdone:
- pop di
- pop es
- pop bp
- ret
-
- DMABuffer endp
-
-
- ; /*\
- ;---|*|---------------====< EnablePCMPlay() >====---------------
- ;---|*|
- ;---|*| Enabled the DAC hardware for polled output (no interrupts)
- ;---|*|
- ;---|*| Entry Conditions:
- ;---|*| None
- ;---|*|
- ;---|*| Exit Conditions:
- ;---|*| AX = 0 good start
- ;---|*| AX = -1 not started, problem occured
- ; \*/
-
- public EnablePCMPlay
- EnablePCMPlay proc
- push es
-
- mov ax,wptr [TheSampleRate+0] ; Validate the sample rate
- or ax,wptr [TheSampleRate+2]
- jz enaPCMPlay_bad ; zero sample rate, bomb out...
-
- call FFAR ptr EnablePlaying ; go for it...
- mov ax,0
- jmp short enaPCMPlay_exit
- ;
- enaPCMPlay_bad:
- mov ax,-1
- ;
- enaPCMPlay_exit:
- pop es
- ret
-
- EnablePCMPlay endp
-
-
- ; /*\
- ;---|*|---------------====< EnablePCMRecord() >====---------------
- ;---|*|
- ;---|*| Enabled the ADC hardware for polled input (no interrupts)
- ;---|*|
- ;---|*| Entry Conditions:
- ;---|*| None
- ;---|*|
- ;---|*| Exit Conditions:
- ;---|*| AX = 0 recording has started
- ;---|*| AX = -1 recording did not start
- ;---|*|
- ; \*/
-
- public EnablePCMRecord
- EnablePCMRecord proc
- push es
-
- mov ax,wptr [TheSampleRate+0] ; Validate the sample rate
- or ax,wptr [TheSampleRate+2]
- jz enaPCMRec_bad
-
- call FFAR ptr EnableRecording ; go for it...
- mov ax,0
- jmp short enaPCMRec_exit
- ;
- enaPCMRec_bad:
- mov ax,-1
- ;
- enaPCMRec_exit:
- pop es
- ret
-
- EnablePCMRecord endp
-
-
- ; /*\
- ;---|*|------====< char far *FindDMABuffer(char far *,int ) >====------
- ;---|*|
- ;---|*| Finds the next 64k boundary starting with dParm1 address
- ;---|*|
- ;---|*| Entry Conditions:
- ;---|*| dParm1 points to a buffer twice the size needed for the DMA
- ;---|*| wParm2 is the size of the DMA buffer (4/8/16/32/64)
- ;---|*|
- ;---|*| Exit Conditions:
- ;---|*| DX:AX = returns buffer pointer on a 64k boundary
- ;---|*| DX:AX = 0 if boundary wraps beyond 1 meg.
- ;---|*|
- ; \*/
-
- public FindDMABuffer
- FindDMABuffer proc
- push bp
- mov bp,sp
-
- mov cx,wParm3 ; get the length
- cmp cx,64 ; 64k buffer requested?
- ja fdb_bad ; too high, exit
- jz fdb_64k ; yes, special case it...
-
- mov ax,1024 ; calculate the length of the DMA buffer
- mul cx
- mov bx,ax ; bx holds the length
-
- cmp cx,4 ; is the buffer less than 4k
- jl fdb_doalign ; yes, move on...
-
- mov dx,0FFFh ; precondition the offset
- and dx,dParm1 ; to align on a 4k page
- xor dParm1,dx
-
- mov ax,00FFh ; precondition the segment
- and ax,dParm1+2 ; to align on a 4k page
- xor dParm1+2,ax
-
- add ax,dx
- neg ax ; if not zero, move the offset to
- sbb ax,ax ; the next 4k page
- and ax,1000h
- add dParm1,ax
-
- sbb ax,ax
- cwd ; dx:ax = ffff if wrapped
-
- mov cx,dParm1 ; get the new offset
- neg cx ; if wrapped to zero, stay here...
- sbb cx,cx ; cx = ffff if not zero
- not ax ; ax = 0000 if wrapped
- and ax,cx ; flush ax if offset is zero
- and dParm1,ax ; adjust offset for special cases
-
- and dx,1000h ; move segment to the next 64k page
- add dParm1+2,dx
- ;
- fdb_doalign:
- mov dx,wptr dParm1+2
- mov ax,dx ; accumulate the offset in ax
- and ax,0fffh ; get the offset portion of the segment
- and dx,0f000h ; make DX a 64k segment register
- mov cl,4
- shl ax,cl ; make the segment an offset
- add ax,wptr dParm1+0 ; accumulate the rest of the offset
- add bx,ax ; does the buffer cross a 64k boundary?
- mov cx,bx ; (save w/o changing flags)
-
- sbb bx,bx ; bx = ffff if crossed a 64k boundary
- and bx,cx ; special case cx=0
- neg bx
- cmc
- sbb bx,bx
-
- and ax,bx ; clear ax if crossed
- not bx ; bx = ffff if crossed, 0000 if not
- and bx,1000h
- add dx,bx ; advance dx if we crossed a 64k boundary
- pop bp
- ret
- ;
- fdb_bad:
- sub ax,ax
- cwd
- pop bp
- ret
- ;
- fdb_64k:
- mov dx,wptr dParm1+2 ; get the segment
- sub ax,ax ; offset is zero
- and dx,0f000h ; find the next segment
- add dx,1000h ; move to next segment
- jc fdb_bad ; if does wraps past 1 meg, flush it...
- pop bp
- ret
-
- FindDMABuffer endp
-
- endif ; PCMOBJ
- if MISC1OBJ
-
- ;
- ; /*\
- ;---|*|---------------====< InitMVSound() >====---------------
- ;---|*|
- ;---|*| Initializes this body of code. It will try to find the int 2F DOS
- ;---|*| interface to the MVPROAS device. Once found, the new state table
- ;---|*| pointer will be loaded.
- ;---|*|
- ;---|*| Entry Conditions:
- ;---|*| None
- ;---|*|
- ;---|*| Exit Conditions:
- ;---|*| DX:AX point to the state table
- ; \*/
-
- public InitMVSound
- InitMVSound proc
- push es
- push di
- mov ax,ds
- mov es,ax
- ;
- ; find the hardware. Should be installed for this to run
- ;
- call MVInitStatePtr ; initialize the state table ptr
-
- cmp _MVHWVersionBits,-1 ; initialized yet?
- jnz @F ; yes, continue on...
- mov ax,USE_ACTIVE_ADDR ; pass in the base address
- push ax
- call mvGetHWVersion ; no, checkout the hardware
- pop ax
- ;
- @@:
- mov ax,wptr [mvhwShadowPointer+0]
- mov dx,wptr [mvhwShadowPointer+2]
-
- pop di
- pop es
- ret
-
- InitMVSound endp
- ;
- endif ; MISC1OBJ
- if PCMOBJ
- ;
- ; /*\
- ;---|*|---------------====< InitPCM() >====---------------
- ;---|*|
- ;---|*| Initializes the PCM code
- ;---|*|
- ;---|*| Entry Conditions:
- ;---|*| None
- ;---|*|
- ;---|*| Exit Conditions:
- ;---|*| AX = Version of this Code
- ; \*/
-
- public InitPCM
- InitPCM proc
- push es
-
- mov [TypeOfSetup],polledmask ; flushes both interrupts
- ; for upcoming calls
- mov al,TheDMAChannel ; initialize the DMA now...
- cbw
- push ax
- call FFAR ptr SelectDMA
- pop ax
-
- mov al,TheIRQChannel ; initialize the IRQ now...
- cbw
- push ax
- call FFAR ptr SelectIRQ ; also removes the IRQ
- pop ax
-
- call FFAR ptr StopPCM ; kill the Audio Spectrum board
-
- mov dx,INTRCTLRST ; flush any pending PCM irq
- xor dx,[_MVTranslateCode] ; xlate the board address
- out dx,al
-
- sub ax,ax
- mov [TypeOfSetup],al ; unknown type
-
- mov wptr [UserRoutine+0],ax
- mov wptr [UserRoutine+2],ax
-
- mov wptr [LinearPtr+0],ax
- mov wptr [LinearPtr+2],ax
- mov wptr [SegmentedPtr+0],ax
- mov wptr [SegmentedPtr+2],ax
-
- mov wptr [DMABuffLength],ax
-
- not al
- mov [StereoMono],al ; mono
-
- mov ax,11025
- cwd
-
- call FFAR ptr _calcsamplerate ; setup the default rate
- mov wptr [TheSampleRate+0],ax
- mov wptr [TheSampleRate+2],dx
-
- mov ax,0003h ; for compatibility, version 00.03
-
- pop es
- ret
-
- InitPCM endp
- ;
- endif ; PCMOBJ
- if PCMOBJ
- ;
- ;
- ; /*\
- ;---|*|---------------====< PausePCM >====---------------
- ;---|*|
- ;---|*| Turn off the h/w timer enables to effectively stop pcm temporarily.
- ;---|*|
- ;---|*| Entry Conditions:
- ;---|*| None
- ;---|*|
- ;---|*| Exit Conditions:
- ;---|*| Nothing
- ;---|*|
- ; \*/
- ;
- public PausePCM
- PausePCM proc
- push es
- push di
- ;
- ; Setup the audio filter sample bits
- ;
- les di,[mvhwShadowPointer]
- mov dx,AUDIOFILT
- xor dx,[_MVTranslateCode] ; xlate the board address
-
- disable
-
- mov al,es:[di._audiofilt]
- and al,not bFIsrate ; flush the enable bits
- mov es:[di._audiofilt],al
- out dx,al
-
- enable
-
- pop di
- pop es
- ret
-
- PausePCM endp
-
- ;
- ; /*\
- ;---|*|---------------====< PCMInfo ( long, int, int, int ) >====---------------
- ;---|*|
- ;---|*| Selects xfer rate & stereo/mono
- ;---|*|
- ;---|*| Entry Conditions:
- ;---|*| Parm #1 (wParm1, wParm2) is the rate
- ;---|*| Parm #2 (wParm3) is the stereo(1) or mono (0)
- ;---|*| Parm #3 (wParm4) is the compression flag
- ;---|*| Parm #4 (wParm5) is the data size (8/12/16 bits per sample)
- ;---|*|
- ;---|*| Exit Conditions:
- ;---|*| AX = 0, good data
- ;---|*| AX = -1, bum transfer rate
- ;---|*|
- ; \*/
-
- public PCMInfo
- PCMInfo proc
- push bp
- mov bp,sp
-
- mov al,wParm4+2 ; get the data size
- cbw
- cmp al,8 ; 8 bit channel?
- jz @F
-
- inc ah
- cmp al,12 ; 12 bit channel
- jz @F
-
- inc ah
- cmp al,16 ; 16 bit channel?
- jnz pcinf_bad ; no, bomb out...
- ;
- @@:
- mov [SampleSize],ah
-
- mov cx,wParm3 ; get the stereo flag
- shr cx,1
- jnz pcinf_bad ; exit bad if not zero
-
- cmc ; set for mono, cleared for stereo
- sbb cx,cx ; make a full bit mask
- mov [StereoMono],cl ; save only valid values
-
- mov ax,dParm1+0 ; get the sample rate
- mov dx,dParm1+2
-
- or cx,cx ; is it mono?
- jnz @F ; yes, skip the doubling
- shl ax,1 ; no, stereo, so double the sample rate
- adc dx,dx
- ;
- @@:
- call FFAR ptr _calcsamplerate
- jc pcinf_bad
- mov wptr [TheSampleRate+0],ax
- mov wptr [TheSampleRate+2],dx
-
- sub ax,ax
- jmp short pcinf_exit
- ;
- pcinf_bad:
- mov ax,-1
- ;
- pcinf_exit:
- pop bp
- ret
-
- PCMInfo endp
- ;
- ;
- ; /*\
- ;---|*|---------------====< PCMPlay() >====---------------
- ;---|*|
- ;---|*| Starts the DMA feeding the DAC
- ;---|*|
- ;---|*| Entry Conditions:
- ;---|*| None
- ;---|*|
- ;---|*| Exit Conditions:
- ;---|*| AX = 0 good start
- ;---|*| AX = -1 not started, problem occured
- ; \*/
-
- public PCMPlay
- PCMPlay proc
- push es
-
- les ax,LinearPtr ; Validate the buffer pointer
- mov bx,es
- or ax,bx
- jz PCMPlay_bad
-
- mov ax,[DMABuffLength] ; Validate the buffer count
- or ax,ax
- jz PCMPlay_bad
-
- mov ax,wptr [TheSampleRate+0] ; Validate the sample rate
- or ax,wptr [TheSampleRate+2]
- jz PCMPlay_bad ; zero sample rate, bomb out...
-
- call FFAR ptr StartPlaying ; go for it...
- sub ax,ax
- jmp short PCMPlay_exit
- ;
- PCMPlay_bad:
- mov ax,-1
- ;
- PCMPlay_exit:
- pop es
- ret
-
- PCMPlay endp
- ;
- ;
- ; /*\
- ;---|*|---------------====< PCMRecord() >====---------------
- ;---|*|
- ;---|*| Starts the DMA reading the ADC
- ;---|*|
- ;---|*| Entry Conditions:
- ;---|*| None
- ;---|*|
- ;---|*| Exit Conditions:
- ;---|*| AX = 0 recording has started
- ;---|*| AX = -1 recording did not start
- ;---|*|
- ; \*/
-
- public PCMRecord
- PCMRecord proc
- push es
-
- les ax,LinearPtr ; Validate the buffer pointer
- mov bx,es
- or ax,bx
- jz PCMRec_bad
-
- mov ax,[DMABuffLength] ; Validate the buffer count
- or ax,ax
- jz PCMRec_bad
-
- mov ax,wptr [TheSampleRate+0] ; Validate the sample rate
- or ax,wptr [TheSampleRate+2]
- jz PCMRec_bad
-
- call FFAR ptr StartRecording ; go for it...
- mov ax,0
- jmp short PCMRec_exit
- ;
- PCMRec_bad:
- mov ax,-1
- ;
- PCMRec_exit:
- pop es
- ret
-
- PCMRecord endp
- ;
- ;
- ; /*\
- ;---|*|---------------====< RemovePCM () >====---------------
- ;---|*|
- ;---|*| Remove our code from the system
- ;---|*|
- ;---|*| Entry Conditions:
- ;---|*| None
- ;---|*|
- ;---|*| Exit Conditions:
- ;---|*| None
- ; \*/
-
- public RemovePCM
- RemovePCM proc
-
- call FFAR ptr StopPCM ; kill the Audio Spectrum board
-
- mov dx,INTRCTLRST ; flush any pending PCM irq
- xor dx,[_MVTranslateCode] ; xlate the board address
- out dx,al
-
- call FFAR ptr _unloadirqvector ; restore the original vector
-
- ret
-
- RemovePCM endp
- ;
- ;
- ; /*\
- ;---|*|---------------====< ResumePCM >====---------------
- ;---|*|
- ;---|*| Turn on the h/w from making interrupt and DMA requests. This assumes
- ;---|*| the hardware has already been setup and is ready to go...
- ;---|*|
- ;---|*| Entry Conditions:
- ;---|*| None
- ;---|*|
- ;---|*| Exit Conditions:
- ;---|*| Nothing
- ;---|*|
- ; \*/
- ;
- public ResumePCM
- ResumePCM proc
- push es
- push di
- ;
- ; Setup the audio filter sample bits
- ;
- les di,[mvhwShadowPointer]
- call FFAR ptr _ASloadtimer0
-
- disable
-
- mov dx,AUDIOFILT
- xor dx,[_MVTranslateCode] ; xlate the board address
- mov al,es:[di._audiofilt]
- or al,bFIsrate ; enable sample rate and buffer timers
- mov es:[di._audiofilt],al
- out dx,al
-
- enable
-
- pop di
- pop es
- ret
-
- ResumePCM endp
- ;
- ;
- ;
- ; /*\
- ;---|*|---------------====< SelectDMA( int ) >====---------------
- ;---|*|
- ;---|*| Selects the DMA channel 0 - 7, excluding 4
- ;---|*|
- ;---|*| Entry Conditions:
- ;---|*| wParm1 points to DMA number (0, 1, 2, 3, 5, 6, 7 )
- ;---|*|
- ;---|*| Exit Conditions:
- ;---|*| AX = 0, good buffer, all okay
- ;---|*| AX = -1, good buffer, all okay
- ;---|*|
- ; \*/
-
- public SelectDMA
- SelectDMA proc
- push bp
- mov bp,sp
-
- mov ax,wParm1 ; get the DMA #
-
- and ax,0111b ; save the channels
-
- mov bx,ax ; get some of the I/O addreses
- shl bx,1 ; into DX
- jnz seldma_02 ; not channel 0, go use it...
- push sp ; 8088/86 class machine?
- pop cx
- cmp cx,sp
- jnz seldma_bad ; yes, can't do channel 0 dma
- ;
- seldma_02:
- mov dx,cs:[dmatable+bx]
- or dx,dx ; valid entry?
- jz seldma_bad ; no, bomb out...
-
- mov TheDMAChannel,al ; select the channel.
- mov bptr OurDMAPageReg,dh ; ...the page register,
- mov bptr OurDMAddress,dl ; ...the address register,
-
- lea bx,DMA1AddrTable ; get the DMA channel addresses
- cmp al,4
- jl seldma_05
- lea bx,DMA2AddrTable ; get the DMA channel addresses
- sub al,4 ; make it zero based
- ;
- seldma_05:
- mov [bx._dmach],al ; save the adjusted dma channel #
- mov [DMAPointer],bx ; save the pointer to all DMA addrs
- sub ax,ax
- pop bp
- ret
- ;
- seldma_bad:
- mov ax,-1
- pop bp
- ret
- ;
- ; dma channels, etc
- ;
- dmatable label word
- dw (CH0PAGEREG SHL 8) + DMAC0ADDR
- dw (CH1PAGEREG SHL 8) + DMAC1ADDR
- dw (CH2PAGEREG SHL 8) + DMAC2ADDR
- dw (CH3PAGEREG SHL 8) + DMAC3ADDR
- dw 0
- dw (CH5PAGEREG SHL 8) + DMA2C5ADDR
- dw (CH6PAGEREG SHL 8) + DMA2C6ADDR
- dw (CH7PAGEREG SHL 8) + DMA2C7ADDR
-
- SelectDMA endp
-
- endif ; PCMOBJ
- if MISC2OBJ
-
- ; /*\
- ;---|*|---------------====< SelectIRQ( int ) >====---------------
- ;---|*|
- ;---|*| Selects the IRQ line for DMA control
- ;---|*|
- ;---|*| Entry Conditions:
- ;---|*| wParm1 points to IRQ number (3,5,6,7)
- ;---|*|
- ;---|*| Exit Conditions:
- ;---|*| AX = 0, good buffer, all okay
- ;---|*| AX = -1, bad IRQ #
- ;---|*|
- ; \*/
-
- public SelectIRQ
- SelectIRQ proc
- push bp
- mov bp,sp
-
- call FFAR ptr _unloadirqvector ; attempt to restore original vector
-
- sub ax,ax ; flush ax for a bad return
-
- mov cx,wParm1 ; get the irq # (2-7,10-12,14-15)
- and cl,0fh ; save only the valid bits
- mov bx,01
- shl bx,cl
-
- and bx,1001110010111100b ; save the mask bit only if the irq
- jz seirqbad ; is a valid selection
-
- mov TheIRQChannel,cl ; save the channel number
-
- cmp cl,8 ; 2nd interrupt controller?
- jb @F ; no, skip
- xchg bh,bl
- ;
- @@:
- mov TheIRQMask,bl
- call FFAR ptr _loadirqvector ; load the new vector
- mov ax,1
- ;
- seirqbad:
- dec ax
- pop bp
- ret
-
- SelectIRQ endp
- ;
- endif ; MISC2OBJ
- if PCMOBJ
-
- ;
- ; /*\
- ;---|*|--------------------====< void StopPCM() >====--------------------
- ;---|*|
- ;---|*| Turn off the PCM timers, interrupts, and state machine.
- ;---|*|
- ;---|*| Entry Conditions:
- ;---|*|
- ;---|*| Exit Conditions:
- ;---|*|
- ;---|*|
- ; \*/
-
- public StopPCM
- StopPCM proc
- push es
- push di
- les di,[mvhwShadowPointer]
- ;
- ; clear the audio filter sample bits
- ;
- mov dx,AUDIOFILT
- xor dx,[_MVTranslateCode] ; xlate the board address
- disable ; drop dead...
- mov al,es:[di._audiofilt] ; get the state
- and al,not (bFIsrate+bFIsbuff) ; flush the sample timer bits
- mov es:[di._audiofilt],al ; save the new state
- out dx,al
- ;
- ; clear the PCM enable bit
- ;
- mov al,es:[di._crosschannel]; get the current cross channel
- and al,not bCCenapcm ; clear the PCM enable bit
- or al,bCCdac
- mov dx,CROSSCHANNEL
- xor dx,[_MVTranslateCode] ; xlate the board address
- out dx,al ; end to the hardware
- mov es:[di._crosschannel],al
- ;
- ; disable the 16 bit stuff
- ;
- test [_MVHWVersionBits],bMV101 ; 101 chip?
- jz stpc02 ; no, don't touch this...
- mov dx,SYSCONFIG2
- xor dx,[_MVTranslateCode] ; xlate the board address
- in al,dx
- and al,not bSC216bit+bSC212bit ; flush the 16 bit stuff
- out dx,al
- ;
- stpc02:
- ;
- ; clear the appropriate Interrupt Control Register bit
- ;
- mov ah,TypeOfSetup
- and ah,bICsamprate+bICsampbuff
- not ah
- mov dx,INTRCTLR
- xor dx,[_MVTranslateCode] ; xlate the board address
- in al,dx
- and al,ah ; kill sample timer interrupts
- out dx,al
- mov es:[di._intrctlr],al
- ;
- ; clear the system interrupt mask only if no other ints are used
- ;
- test al,fICintmaskbits XOR (bICsamprate+bICsampbuff)
- jnz stpc10
- ;
- ; select the correct IRQ controller, then mask it...
- ;
- cmp TheIRQChannel,2 ; Chained IRQ channel?
- jz stpc10 ; yes, leave it open...
-
- mov dx,IRQ1MASKREG
- cmp TheIRQChannel,8 ; 2nd IRQ controller?
- jl stpc05
- mov dl,IRQ2MASKREG
- ;
- stpc05:
- in al,dx
- or al,[TheIRQMask]
- out dx,al
- enable ; start again...
- ;
- stpc10:
- call FFAR ptr KillDMA ; stop the DMA too...
-
- mov [StatusWord],0 ; inactive, available
-
- pop di
- pop es
- ret
-
- StopPCM endp
-
- ;
- ; /*\
- ;---|*|---------------====< UserFunc((*long)()) >====---------------
- ;---|*|
- ;---|*| Call back routine when Half way buffer is full/empty.
- ;---|*|
- ;---|*| Entry Conditions:
- ;---|*| dParm1 points to the user routine
- ;---|*|
- ;---|*| Exit Conditions:
- ;---|*| Nothing
- ;---|*|
- ; \*/
-
- public UserFunc
- UserFunc proc
- push bp
- mov bp,sp
-
- push es
-
- les ax,dParm1 ; get the routine
- mov dx,es
- or dx,ax
- jz usfu_bad
-
- mov wptr [UserRoutine+0],ax
- mov wptr [UserRoutine+2],es
- ;
- usfu_bad:
- pop es
- pop bp
- ret
-
- UserFunc endp
-
- endif ; PCMOBJ
-
- ;
- ;
- ;----------------------------========================--------------------------
- ;----------------------------========================--------------------------
- ;----------------------------========================--------------------------
- ;
- ;
- ; PPPPPPPP CCCCCC MMM MMM
- ; PPPPPPPP CCCCCCC MMMM MMMM
- ; PPP PPP CCC MMMMM MMMMM
- ; PPP PPP CCC MMMMMM MMMMMM
- ; PPPPPPPP CCC MMM MMMMM MMM
- ; PPPPPPPP CCC MMM MMM MMM
- ; PPP CCC MMM M MMM
- ; PPP CCC MMM MMM
- ; PPP CCCCCCC MMM MMM
- ; PPP CCCCCC MMM MMM
- ;
- ; rrrrr oooo uu uu tttttt iiiiii nn nn eeeee sssss
- ; rr rr oo oo uu uu tt ii nnn nn ee ss
- ; rrrrrr oo oo uu uu tt ii nnnnnn eeeeee ssss
- ; rr rr oo oo uu uu tt ii nn nnn ee ss
- ; rr rr oooo uuuuuu tt iiiiii nn nn eeeee sssss
- ;
- ;
- ;
- ;----------------------------========================--------------------------
- ;----------------------------========================--------------------------
- ;----------------------------========================--------------------------
-
- if PCMOBJ
-
- ;
- ;----------------------------====< _ASloadtimer0 >====-------------------------
- ;
- ;
- ; Setup the Sample Timer (T0 & square wave output)
- ;
- ; Entry Conditions:
- ; ES:DI point to the state table.
- ; Exit Conditions:
- ; The timer is loaded with the new sample rate
- ;
- public _ASloadtimer0
- _ASloadtimer0 proc
-
- mov al,00110110b ; 36h Timer 0 & square wave
- mov dx,TMRCTLR
- xor dx,[_MVTranslateCode] ; xlate the board address
-
- pushf
- cli
-
- out dx,al ; setup the mode, etc
- mov es:[di._tmrctlr],al
-
- mov ax,es:[di._samplerate] ; pre-calculated & saved in prior code
- mov dx,SAMPLERATE
- xor dx,[_MVTranslateCode] ; xlate the board address
- out dx,al ; output the timer value
-
- pause
-
- xchg ah,al
- out dx,al
-
- popf
- ret
-
- _ASloadtimer0 endp
-
- ;
- ;----------------------------====< _ASloadtimer1 >====-------------------------
- ;
- public _ASloadtimer1
- _ASloadtimer1 proc
- push es
- push di
- les di,[mvhwShadowPointer]
-
- push dx ; do not disturb any register
- push ax
-
- mov al,01110100b ; 74h Timer 1 & rate generator
- mov dx,TMRCTLR
- xor dx,[_MVTranslateCode] ; xlate the board address
-
- disable
-
- out dx,al
- mov es:[di._tmrctlr],al ; local timer control register
-
- pop ax
-
- mov dx,SAMPLECNT
- xor dx,[_MVTranslateCode] ; xlate the board address
- mov es:[di._samplecnt],ax
-
- out dx,al
- pause
- xchg ah,al
- out dx,al
-
- enable
-
- xchg ah,al
-
- pop dx
- pop di
- pop es
- ret
-
- _ASloadtimer1 endp
- ;
- ;
- ;--------------------------====< _calcsamplerate >====-------------------------
- ;
- ; Calculate the H/W timer value (internal routine)
- ;
- ; Entry Conditions:
- ; DX:AX hold the users requested sample rate
- ;
- ; Exit Conditions:
- ; carry SET if bad value
- ; No registers modified
- ;
- ;
- public _calcsamplerate
- _calcsamplerate proc
- push es
- push di
- les di,[mvhwShadowPointer]
-
- push ax
- push bx
- push cx
- push dx
- ;
- ; make sure sample rate does not exceed 88200
- ;
- mov cx,ax ; do 32 bit subtraction
- sub cx,05888H+1 ; 157C0 is decimal 88200
- mov cx,dx ; too high?
- sbb cx,00001H ; over 88200 khz is bad
- jnc CaSaRa_bad ; bomb out greater than 88200
- ;
- ; load 1193180 in bx:cx for 32x32 bit division
- ;
- mov bx,0012h
- mov cx,34dch ; load bx:cx with 1193180
-
- xchg bx,dx ; dx:ax = 1193180
- xchg cx,ax ; bx:cx = sample rate
- ;
- ; since we don't have 32x32 bit division, we'll cheat here. No great loss.
- ;
- or bx,bx ; is value over 64k?
- jz @F ; no, continue on...
- shr bx,1 ; yes, divide all by 2
- rcr cx,1 ; to allow division of 32x16 bits
- shr dx,1
- rcr ax,1
- ;
- @@:
- div cx
- mov es:[di._samplerate],ax ; save just the low order
- clc
- jmp short CaSaRa_exit
- ;
- CaSaRa_bad:
- stc
- ;
- CaSaRa_exit:
- pop dx
- pop cx
- pop bx
- pop ax
-
- pop di
- pop es
- ret
-
- _calcsamplerate endp
- ;
- ;
- ;----------------------------====< EnableRecording >====-----------------------
- ;
- public EnableRecording
- EnableRecording proc
- ;
- ; Save the type of setup. It contains the interrupt masks needed
- ;
- mov [TypeOfSetup],POLLEDINPUT
- mov [PCMDirection],0 ; bit 6 is cleared (DAC enable)
- ;
- ; enable the onboard sampling timers, disable interrupts
- ;
- call FFAR ptr SetupPCMPolledIO ; Setup the MV Hardware
- mov StatusWord,2 ; set the global status word
- ret
-
- EnableRecording endp
- ;
- ;
- ;----------------------------====< EnablePlaying >====-------------------------
- ;
- public EnablePlaying
- EnablePlaying proc
- ;
- ; Save the type of setup. It contains the interrupt masks needed
- ;
- mov [TypeOfSetup],POLLEDOUTPUT
- mov [PCMDirection],bCCdac ; bit d6 of interrupt control register
- ;
- ; enable the onboard sampling timers, etc.
- ;
- call FFAR ptr SetupPCMPolledIO ; Setup the MV Hardware
- mov StatusWord,1 ; set the global status word
-
- ret
-
- EnablePlaying endp
- ;
- endif ; PCMOBJ
- if MISC2OBJ
- ;
- ;---------------------------====< _getirqoffset >====--------------------------
- ;
- ; takes the IRQ # & converts to offset in vector table
- ;
- ;
- public _getirqoffset
- _getirqoffset proc
- sub bh,bh
- shl bx,1
- mov bx,cs:[irqoffsets+bx]
- ret
-
- irqoffsets label word
- dw (8+0)*4 ; IRQ 0 clock timer
- dw (8+1)*4 ; IRQ 1 keyboard
- dw (8+2)*4 ; IRQ 2 available
- dw (8+3)*4 ; IRQ 3 COM2
- dw (8+4)*4 ; IRQ 4 COM1
- dw (8+5)*4 ; IRQ 5 available
- dw (8+6)*4 ; IRQ 6 floppy controller
- dw (8+7)*4 ; IRQ 7 LPT
- dw (70h+0)*4 ; IRQ 8 real time clock
- dw (70h+1)*4 ; IRQ 9 Re-Directed IRQ2
- dw (70h+2)*4 ; IRQ a available
- dw (70h+3)*4 ; IRQ b available
- dw (70h+4)*4 ; IRQ c available
- dw (70h+5)*4 ; IRQ d coprocessor
- dw (70h+6)*4 ; IRQ e Hard Disk
- dw (70h+7)*4 ; IRQ f available
-
- _getirqoffset endp
- ;
- endif ; MISC2OBJ
- if PCMOBJ
- ;
- ;------------------------------====< KillDMA >====-----------------------------
- ;
- ; KillDMA -- flush our settings
- ;
- ; Entry Conditions:
- ;
- KillDMA proc
- push es
- push di
-
- cmp StatusWord,0 ; is there any activity?
- jz kidm_none
-
- mov di,[DMAPointer] ; get the DMA pointer
- sub dx,dx ; clear out the high byte
- ;
- ; mask out the DMA to stop it
- ;
- disable
- mov al,[di._dmach] ; get the adjusted dma channel #
- or al,0100b ; disable the DMA
- mov dl,[di._dmawrsmr]
- out dx,al
- ;
- ; remove control on the DRQ line
- ;
- les di,[mvhwShadowPointer]
-
- mov al,es:[di._crosschannel]; get the state
- mov dx,CROSSCHANNEL
- xor dx,[_MVTranslateCode] ; xlate the board address
- and al,not bCCdrq ; clear the DRQ bit
- out dx,al
-
- mov es:[di._crosschannel],al; and save the new state
- enable
- ;
- kidm_none:
- pop di
- pop es
- ret
-
- KillDMA endp
- ;
- endif ; PCMOBJ
- if PCMOBJ
- ;
- ;------------------------------====< LoadDMA >====-----------------------------
- ;
- ; LoadDMA -- Load the DMA controller to read/write data to the MV board
- ;
- ; Entry Conditions:
- ;
- ;
- public LoadDMA
- LoadDMA proc
- push es
- push di
- push si
-
- les di,[mvhwShadowPointer]
-
- mov si,[DMAPointer] ; point to the DMA controller table
- sub dx,dx ; clear out the high byte
- ;
- ; kill the dma until all programming is done
- ;
- mov al,[si._dmach] ; get the adjusted dma channel #
- or al,0100b ; causes all DMA to be suspended
- mov dl,[si._dmawrsmr]
- out dx,al
- ;
- ; program the mode
- ;
- mov al,[TheDMAmode] ; get the app's desired mode
- or al,[si._dmach] ; merge the adjusted dma channel #
- mov dl,[si._dmawrmode]
- out dx,al
- ;
- ; adjust the address for a 16 bit channel
- ;
- mov ax,wptr [LinearPtr+2] ; get the page #
- ;
- ; setup the page register
- ;
- mov dx,[OurDMAPageReg]
- out dx,al
- mov bl,al
- ;
- ; reset the flip-flop, then output the address, then count
- ;
- mov dl,[si._dmaclear] ; dh is still clear...
- out dx,al ; flush...
-
- mov ax,wptr [LinearPtr+0] ; get the low 16 bits
- cmp si,offset DMA1AddrTable ; 1st DMA controller?
- jz @F ; yes, continue on...
- shr bl,1 ; no, divide the buffer in half
- rcr ax,1 ; by shifting 17 bits
- ;
- @@:
- mov dx,[OurDMAddress]
- out dx,al
- pause
- xchg ah,al
- out dx,al
-
- mov ax,[DMABuffLength]
- cmp si,offset DMA1AddrTable ; is this the 2nd dma controller?
- jz lodma03 ; no, use the full length
- shr ax,1
- inc dx ; move to next port address
- ;
- lodma03:
- inc dx ; move to next port address
- out dx,al
- pause
- xchg ah,al
- out dx,al
- ;
- ; before we enable the DMA, let's make sure the DRQ is controlled, not floating
- ;
- mov al,es:[di._crosschannel]; get the state
- mov dx,CROSSCHANNEL
- xor dx,[_MVTranslateCode] ; xlate the board address
- or al,bCCdrq ; set the DRQ bit to control it
- out dx,al
- mov es:[di._crosschannel],al; and save the new state
- ;
- ; re-enable the dma now that all programming is done
- ;
- mov al,[si._dmach] ; get the adjusted dma channel #
- sub dx,dx ; clear dh
- mov dl,[si._dmawrsmr]
- out dx,al ; & let'er loose (not moving though...)
- ;
- ; all done, return home...
- ;
- pop si
- pop di
- pop es
- ret
-
- LoadDMA endp
- ;
- endif ; PCMOBJ
- if MISC2OBJ
- ;
- ;--------------------------====< _loadirqvector >====--------------------------
- ;
- ; Restore the original vector
- ;
- ; Entry Conditions:
- ;
- ; Exit Conditions:
- ; Nothing
-
- public _loadirqvector
- _loadirqvector proc
- push es
-
- les ax,OldIRQRoutine
- mov bx,es
- or bx,ax
- jnz @F
-
- lea ax,OurIntVector
- mov dx,cs
-
- mov bl,[TheIRQChannel]
- call FFAR ptr _getirqoffset
-
- push ds
- sub cx,cx
- mov ds,cx
-
- disable
- xchg ds:[bx+0],ax
- xchg ds:[bx+2],dx
- enable
-
- pop ds
-
- mov wptr [OldIRQRoutine+0],ax
- mov wptr [OldIRQRoutine+2],dx
- ;
- @@:
- pop es
- ret
-
- _loadirqvector endp
- ;
- endif ; MISC2OBJ
- if MISC2OBJ
- ;
- ;---------------------------====< OurIntVector >====---------------------------
- ;
- ; OurIntVector -- process DMA interrupts
- ;
-
- intsemaphore db -1 ; -1 free, 0+ locked
-
- public OurIntVector
- OurIntVector proc
- push dx
- push ax
- push ds
-
- if MODELSIZE eq 0
- mov ax,cs ; tiny (.com) model uses cs segment
- else
- mov ax,@data ; all others use their data segments
- endif
- mov ds,ax
-
- mov dx,INTRCTLRST ; clear the interrupt
- xor dx,[_MVTranslateCode] ; xlate the board address
- in al,dx
-
- test al,bISsampbuff ; our interrupt?
- jz skip_int ; no, continue on...
-
- out dx,al ; yes, flush it...
-
- mov al,EOI ; clear the interrupt
- cmp TheIRQChannel,8 ; 2nd IRQ controller?
- jb @F
- out IRQ2ACKREG,al
- ;
- @@:
- out IRQ1ACKREG,al
-
- inc [NumberOfInterrupts]
-
- inc cs:[intsemaphore]
- jnz oiv_done
-
- sti ; let interrupts go while we work
-
- cmp wptr [UserRoutine+2],0 ; call the user function?
- jz oiv_done ; no, just exit
-
- call dword ptr [UserRoutine]
- ;
- oiv_done:
- dec cs:[intsemaphore]
- ;
- exit_int:
- pop ds
- pop ax
- pop dx
- iret
- ;
- skip_int:
- pushf
- call dword ptr ds:[OldIRQRoutine] ; perform the old interrupt
- jmp short exit_int
-
- OurIntVector endp
- ;
- endif ; MISC2OBJ
- if PCMOBJ
- ;
- ;---------------------------====< SetupPCMDMAIO >====--------------------------
- ;
- ; SetupPCMDMAIO -- Setup to output to the DAC
- ;
- public SetupPCMDMAIO
- SetupPCMDMAIO proc
- push es
- push di
- les di,[mvhwShadowPointer]
- ;
- ; setup the sample rate timer
- ;
- call _ASloadtimer0
- ;
- ; Setup the Sample Buffer Counter Timer (T1 & rate generator)
- ;
- mov ax,[DMABuffLength] ; get the count
- sub dx,dx
- add ax,1 ; make it 1 based (1 - 64k)
- adc dx,dx
- mov cl,[DMABUffDivides] ; get the buffer size
- sub ch,ch
- div cx ; now, we must be flexible
-
- mov bl,[TheDMAChannel] ; is this a 16 bit channel?
- mov bh,[SampleSize] ; CX = sample size, channel
-
- sub cx,cx ; ch = multiplier, cl=divider
- cmp bx,0003h ; 8 bits on 8 bit channel?
- jbe @F ; yes, continue on...
-
- inc cx ; divide by 2
- cmp bx,0007h ; 8 bits on 16 bit channel?
- jbe @F ; yes, continue on...
-
- xchg ch,cl ; multiply by 2
- cmp bx,0203h ; 16 bits on 8 bit channel?
- jbe @F ; yes, continue on...
- sub cx,cx ; no multiply or divide
- ;
- @@:
- shr ax,cl ; if 8 on 16 divide by 2
- xchg ch,cl
- shl ax,cl ; if 16 on 8 multiply by 2
-
- sub cx,cx ; The buffer size is # of bytes, so
- neg bh ; we must convert it to the data size
- adc cx,cx
- shr ax,cl
-
- call FFAR ptr _ASloadtimer1
- ;
- ; Setup the system interrupt mask (IRQ mask)
- ;
- mov dx,IRQ1MASKREG
- cmp TheIRQChannel,8 ; 2nd IRQ controller?
- jl @F
- mov dl,IRQ2MASKREG
- ;
- @@:
- in al,dx ; get the mask
- mov ah,TheIRQMask
- not ah
- and al,ah ; unmask the correct IRQ
- out dx,al ; then let the system know
- ;
- ; Setup the Interrupt Control Register
- ;
- mov dx,INTRCTLRST ; flush any pending interrupts
- xor dx,[_MVTranslateCode] ; xlate the board address
- out dx,al ; of the PCM circuitry
-
- mov dx,INTRCTLR
- xor dx,[_MVTranslateCode] ; xlate the board address
- in al,dx ; get the real mask
- or al,bICsampbuff ; interrupt on sample buffer count
- out dx,al ; send it..
- mov es:[di._intrctlr],al ; save it..
- ;
- ; enable the 12/16 bit stuff
- ;
- test [_MVHWVersionBits],bMV101 ; 101 chip?
- jz sdhpas1_05 ; no, don't touch this...
-
- mov cx,((NOT(bSC216bit+bSC212bit))*256) + bSC216bit+bSC212bit
- cmp [SampleSize],1 ; 12 bit?
- jz @F
- mov cx,((NOT(bSC216bit+bSC212bit))*256) + bSC216bit
- cmp [SampleSize],2 ; 16 bit?
- jz @F
- mov cx,((NOT(bSC216bit+bSC212bit))*256) + 0
- ;
- @@:
- mov dx,SYSCONFIG2
- xor dx,[_MVTranslateCode] ; xlate the board address
- in al,dx
- and al,ch ; clear the bits
- or al,cl ; set the appropriate bits
- out dx,al
- ;
- sdhpas1_05:
- ;
- ; setup the direction, stereo/mono and DMA enable bits
- ;
- mov al,bCCmono ; get the stereo/mono mask bit
- and al,[StereoMono] ; al = bCCmono if in mono mode
- or al,[PCMDirection] ; get the direction bit mask
- or al,bCCenapcm ; enable the PCM state machine
- mov dx,CROSSCHANNEL
- xor dx,[_MVTranslateCode] ; xlate the board address
- mov ah,0fh + bCCdrq ; get a mask to load non PCM bits
- and ah,es:[di._crosschannel]; grab all but PCM/DRQ/MONO/DIRECTION
- or al,ah ; merge the two states
- xor al,bCCenapcm ; disable the PCM bit
- out dx,al ; send to the hardware
- xor al,bCCenapcm ; enable the PCM bit
- out dx,al ; send to the hardware
- mov es:[di._crosschannel],al; and save the new state
- ;
- ; Setup the audio filter sample bits
- ;
- mov al,es:[di._audiofilt]
- or al,(bFIsrate+bFIsbuff) ; enable the sample count/buff counters
- mov dx,AUDIOFILT
- xor dx,[_MVTranslateCode] ; xlate the board address
- out dx,al
- mov es:[di._audiofilt],al
-
- mov NumberOfInterrupts,0
-
- enable ; Fly, baby Fly!!!
-
- pop di
- pop es
- ret
-
- SetupPCMDMAIO endp
- ;
- ;
- ;---------------------------====< SetupPCMPolledIO >====-----------------------
- ;
- ; SetupPCMPolledIO -- Setup to read/write to the ADC/DAC in a polled fashion
- ;
- public SetupPCMPolledIO
- SetupPCMPolledIO proc
- push es
- push di
- les di,[mvhwShadowPointer]
- ;
- ; Setup the Sample Timer (T0 & square wave output)
- ;
- call _ASloadTimer0
- ;
- ; Setup the Sample Buffer Counter Timer (T1 & rate generator)
- ;
- mov ax,1 ; get the count
- call FFAR ptr _ASloadtimer1
- ;
- ; Setup the Interrupt Control Register
- ;
- mov dx,INTRCTLR
- xor dx,[_MVTranslateCode] ; xlate the board address
- in al,dx ; get the real mask
- or al,bICsampbuff+bICsamprate ; enable both sample timer ints
- out dx,al ; send it...
- mov es:[di._intrctlr],al ; save it...
- ;
- ; enable the 16 bit stuff
- ;
- test [_MVHWVersionBits],bMV101 ; 101 chip?
- jz sphpas1_05 ; no, don't touch this...
-
- mov cx,((NOT(bSC216bit+bSC212bit))*256) + bSC216bit+bSC212bit
- cmp [SampleSize],1 ; 12 bit?
- jz @F
- mov cx,((NOT(bSC216bit+bSC212bit))*256) + bSC216bit
- cmp [SampleSize],2 ; 16 bit?
- jz @F
- mov cx,((NOT(bSC216bit+bSC212bit))*256) + 0
- ;
- @@:
- mov dx,SYSCONFIG2
- xor dx,[_MVTranslateCode] ; xlate the board address
- in al,dx
- and al,ch ; clear the bits
- or al,cl ; set the appropriate bits
- out dx,al
- ;
- sphpas1_05:
- ;
- ; setup the direction, stereo/mono and DMA enable bits
- ;
- mov al,bCCmono ; get the stereo/mono mask bit
- and al,[StereoMono] ; al = bCCmono if in mono mode
- or al,[PCMDirection] ; get the direction bit mask
- or al,bCCenapcm + bCCdrq ; enable the PCM & set DRQ for NOT mask
- mov dx,CROSSCHANNEL
- xor dx,[_MVTranslateCode] ; xlate the board address
- mov ah,0fh ; get a mask to load the non-PCM bits
- and ah,es:[di._crosschannel]; grab all but PCM/DRQ/MONO/DIRECTION
- or al,ah ; merge the two states
- xor al,bCCenapcm + bCCdrq ; disable the PCM & DRQ
- out dx,al ; send to the hardware
- xor al,bCCenapcm ; enable the PCM
- out dx,al
- mov es:[di._crosschannel],al; and save the new state
- ;
- ; Setup the audio filter sample bits to enable sample timer/count
- ;
- mov al,es:[di._audiofilt]
- or al,(bFIsrate+bFIsbuff) ; enable the sample timer/counter
- mov dx,AUDIOFILT
- xor dx,[_MVTranslateCode] ; xlate the board address
- out dx,al
- mov es:[di._audiofilt],al
-
- sub ax,ax
- mov NumberOfInterrupts,ax
-
- enable
-
- pop di
- pop es
- ret
-
- SetupPCMPolledIO endp
- ;
- ;
- ;----------------------------====< StartPlaying >====--------------------------
- ;
- public StartPlaying
- StartPlaying proc
- ;
- ; Save the type of setup. It contains the interrupt masks needed
- ;
- mov [TypeOfSetup],DMAOUTPUT
- mov [PCMDirection],bCCdac ; bit d6 of interrupt control register
- ;
- ; Select the DMA mode for playing
- ;
- mov al,10h ; auto init bit on 8237 chip
- and al,[DMAAutoInit] ; al may have the auto-init bit
- or al,48h ; merge in the rest of the DMA bits
- mov TheDMAMode,al ; save the mode
- ;
- ; Program the DMA, then our board circuitry to start the interrupts
- ;
- call LoadDMA ; setup the DMA controller
- call SetupPCMDMAIO ; Setup the MV Hardware
-
- mov StatusWord,1 ; set the global status word
-
- ret
-
- StartPlaying endp
- ;
- ;
- ;---------------------------====< StartRecording >====-------------------------
- ;
- public StartRecording
- StartRecording proc
- ;
- ; Save the type of setup. It contains the interrupt masks needed
- ;
- mov [TypeOfSetup],DMAINPUT
- mov [PCMDirection],00h ; bit d6 of interrupt control register
- ;
- ; Select the DMA mode for recording
- ;
- mov al,10h ; auto init bit on 8237 chip
- and al,[DMAAutoInit] ; al may have the auto-init bit
- or al,44h ; merge in the rest of the DMA bits
- mov TheDMAMode,al ; save the mode
- ;
- ; Program the DMA, then our board circuitry to start the interrupts
- ;
- call LoadDMA ; setup the DMA controller
- call SetupPCMDMAIO ; Setup the MV Hardware
-
- mov StatusWord,2 ; set the global status word
- ret
-
- StartRecording endp
- ;
- endif ; PCMOBJ
- if MISC2OBJ
- ;
- ;---------------------====< _unloadirqvector >====---------------
- ;
- ; Restore the original vector
- ;
- ; Entry Conditions:
- ; dParm1 points to the user routine
- ;
- ; Exit Conditions:
- ; Nothing
- ;
- ;
- public _unloadirqvector
- _unloadirqvector proc
- push es
-
- les ax,OldIRQRoutine
- mov bx,es
- or bx,ax
- jz @F
-
- mov bl,[TheIRQChannel]
- call _getirqoffset
-
- push ds
- sub cx,cx
- mov ds,cx
-
- disable
- mov ds:[bx+0],ax
- mov ds:[bx+2],es
- enable
-
- pop ds
-
- sub ax,ax
- mov wptr [OldIRQRoutine+0],ax
- mov wptr [OldIRQRoutine+2],ax
- ;
- @@:
- pop es
- ret
-
- _unloadirqvector endp
-
- endif ; MISC2OBJ
-
- end
-
-